﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using EngineOfEvermore.Scene;
using System.Diagnostics;
using GorgonLibrary.Graphics;
using EngineOfEvermore.Common;
using GorgonLibrary;
using EngineOfEvermore.Scene.Visual;

namespace EngineOfEvermore.Editor.Common
{
    public partial class SceneView : UserControl
    {
        class MouseEventHandler
        {
            enum State
            { 
                Idle,
                Moving
            };

            readonly SceneView _owner;
            State _state;
            Vector2d _lastMousePosition;

            public bool IsSubscribedToMouseEvents
            {
                get;
                private set;
            }

            public MouseEventHandler( SceneView owner )
            {
                _owner = owner;
            }

            public void SubscribeToMouseEvents()
            {
                if ( !this.IsSubscribedToMouseEvents )
                {
                    _owner.MouseDown += _owner_MouseDown;
                    _owner.MouseUp += _owner_MouseUp;
                    _owner.MouseMove += _owner_MouseMove;
                    _owner.MouseWheel += _owner_MouseWheel;

                    this.IsSubscribedToMouseEvents = true;
                }
            }

            public void UnsubscribeFromMouseEvents()
            {
                if ( this.IsSubscribedToMouseEvents )
                {
                    _owner.MouseDown -= _owner_MouseDown;
                    _owner.MouseUp -= _owner_MouseUp;
                    _owner.MouseMove -= _owner_MouseMove;
                    _owner.MouseWheel -= _owner_MouseWheel;

                    this.IsSubscribedToMouseEvents = false;
                }
            }

            void _owner_MouseWheel( object sender, MouseEventArgs e )
            {
                if ( e.Delta > 0 )
                {
                    _owner.Camera.Scale *= 1.1f;
                }
                else
                {
                    _owner.Camera.Scale /= 1.1f;
                }
            }

            void _owner_MouseMove( object sender, MouseEventArgs e )
            {
                if ( _state == State.Moving )
                {
                    Vector2d currentPosition = new Vector2d( e.X, e.Y );
                    Vector2d diff = currentPosition - _lastMousePosition;

                    diff /= _owner.Camera.Scale;

                    _owner.Camera.Position -= diff;

                    _lastMousePosition = currentPosition;
                }
            }

            void _owner_MouseUp( object sender, MouseEventArgs e )
            {
                if ( _state == State.Moving )
                {
                    _state = State.Idle;
                }
            }

            void _owner_MouseDown( object sender, MouseEventArgs e )
            {
                if ( e.Button == MouseButtons.Right )
                {
                    _state = State.Moving;
                    _lastMousePosition = new Vector2d( e.X, e.Y );
                }
            }
        }

        GorgonRenderTargetManager _renderTargetManager;
        RenderWindow _renderWindow;
        SceneGraph _sceneGraph;
        bool _initialized;
        bool _doRender = true;
        bool _clearBeforeDrawing = true;
        String _renderWindowName;
        Camera _camera = new Camera();
        MouseEventHandler _mouseEventHandler;
        bool _enableMouseCameraControl = true;

        static int _renderWindowCounter;

        public String RenderWindowName
        {
            get { return _renderWindowName; }
            set { _renderWindowName = value; }
        }

        public SceneView()
        {
            InitializeComponent();

            _mouseEventHandler = new MouseEventHandler( this );
            _mouseEventHandler.SubscribeToMouseEvents();
        }

        public void Initialize( GorgonRenderTargetManager renderTargetManager )
        {
            Debug.Assert( renderTargetManager != null );

            _renderTargetManager = renderTargetManager;

            if ( String.IsNullOrEmpty( _renderWindowName ) )
            {
                _renderWindowName = "SceneViewRenderImage" + _renderWindowCounter++;
            }

            _renderWindow = new RenderWindow( _renderWindowName, this, false );

            if ( _doRender )
            {
                _renderTargetManager.Add( _renderWindow, _render );
            }

            _camera.ViewportSize = this.ClientSize;

            _initialized = true;
        }

        public SceneGraph SceneGraph
        {
            get { return _sceneGraph; }
            set { _sceneGraph = value; }
        }

        public Camera Camera
        {
            get { return _camera; }
        }

        [DefaultValue( true )]
        [Category( "SceneView" )]
        public bool DoRender
        {
            get 
            { 
                return _doRender;
            }
            set 
            {
                if ( _doRender != value )
                {
                    _doRender = value;

                    if ( _initialized )
                    {
                        if ( _doRender )
                        {
                            _renderTargetManager.Add( _renderWindow, _render );
                        }
                        else
                        {
                            _renderTargetManager.Remove( _renderWindow );
                        }
                    }
                }
            }
        }

        [DefaultValue( true )]
        [Category( "SceneView" )]
        public bool ClearBeforeDrawing
        {
            get { return _clearBeforeDrawing; }
            set { _clearBeforeDrawing = value; }
        }

        [DefaultValue( true )]
        public bool EnableMouseCameraControl
        {
            get { return _enableMouseCameraControl; }
            set
            {
                _enableMouseCameraControl = value;

                if ( _enableMouseCameraControl )
                {
                    _mouseEventHandler.SubscribeToMouseEvents();
                }
                else
                {
                    _mouseEventHandler.UnsubscribeFromMouseEvents();
                }
            }
        }

        void _render( FrameEventArgs e )
        {
            Debug.Assert( _initialized );
            Debug.Assert( _renderWindow != null );

            bool needUpdate = false;

            if ( _clearBeforeDrawing || _sceneGraph != null )
            {
                Gorgon.CurrentRenderTarget = _renderWindow;
            }

            if ( _clearBeforeDrawing )
            {
                _renderWindow.Clear( Color.Green );
                needUpdate = true;
            }

            if ( _sceneGraph != null )
            {
                _camera.ApplyTransform(); 

                _sceneGraph.Draw( _camera.GetDisplayedArea() , e );
                needUpdate = true;
            }

            if ( needUpdate )
            {
                _renderWindow.Update();
            }
        }

        void _clientSizeChanged( object sender, EventArgs e )
        {
            _camera.ViewportSize = this.ClientSize;
        }
    }
}
